package com.runda.sec;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.FilterInvocation;
import org.springframework.stereotype.Service;
import org.springframework.util.AntPathMatcher;

import com.bbjob.mapper.SysFunctionMapper;
import com.bbjob.mapper.SysRoleFunctionMapper;
import com.bbjob.model.SysFunction;
import com.bbjob.model.SysRoleFunction;

import tk.mybatis.mapper.entity.Example;
@Service
public class CustomAccessDecisionManager implements AccessDecisionManager,ApplicationRunner{
	Logger logger=LoggerFactory.getLogger(getClass());
	@Resource
	private SysFunctionMapper funcMapper;
	@Resource
	private SysRoleFunctionMapper roleFuncMapper;
	private AntPathMatcher mahtcher=new AntPathMatcher();
	private static Map<String,ArrayList<String>> FuncRoleMap=new HashMap<String,ArrayList<String>>();
	private static Map<String,SysFunction> FuncMap=new HashMap<String,SysFunction>();
	public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
			throws AccessDeniedException, InsufficientAuthenticationException {
		configAttributes.forEach(attr->{
			if("permitAll".equals(attr.toString()))
				return;
		});
		if(authentication.getPrincipal() instanceof UserDetails) {
			if(authentication.getAuthorities()==null||authentication.getAuthorities().isEmpty()) {
				throw new AccessDeniedException("无权限访问，请联系管理员");
			}
			FilterInvocation filterInv=(FilterInvocation)object;
			authentication.getAuthorities().forEach(item->{
				if("-1".equals(item.getAuthority())){
					return ;
				}
				FuncMap.forEach((key,sysfun)->{
					if(logger.isDebugEnabled()) {
						logger.debug("url:"+filterInv.getRequestUrl());
					}	
					
					if(mahtcher.match(key, filterInv.getRequestUrl())) {
						String funId=sysfun.getId().toString();
						if(FuncRoleMap.containsKey(funId)) {
							authentication.getAuthorities().forEach(authority->{
								FuncRoleMap.get(funId).forEach(role->{
									if(role.equals(authority.getAuthority()))
										if(logger.isDebugEnabled()) {
											logger.debug("验证通过。。。");
										}	
										return;
								});							
							});
							throw new AccessDeniedException("无权限访问，请联系管理员");
						}
					}
				});
			});
			return ;
		}
		throw new InsufficientAuthenticationException("token异常");
		
	}

	@Override
	public boolean supports(ConfigAttribute attribute) {		
		return true;
	}

	@Override
	public boolean supports(Class<?> clazz) {
		return true;
	}

	
	public void refreshSysFuncStore() {
		FuncMap.clear();
		Example example=new Example(SysFunction.class);
		example.createCriteria().andIsNotNull("url");
		List<SysFunction> funList=this.funcMapper.selectByExample(example);
		funList.forEach(item->{
			FuncMap.put(item.getUrl(), item);
		});
	}
	public void refreshRoleFuncStore() {
		FuncRoleMap.clear();
		List<SysRoleFunction> roleFuncList= roleFuncMapper.selectAll();
		roleFuncList.forEach(roleFunc->{
			
			if(FuncMap.containsKey(roleFunc.getFunctionId()+"")){
				FuncRoleMap.get(roleFunc.getFunctionId()+"").add(roleFunc.getRoleId()+"");
			}else {
				ArrayList<String> list=new ArrayList<String>();
				list.add(roleFunc.getRoleId()+"");
				FuncRoleMap.put(roleFunc.getFunctionId()+"", list);
			}
		});
	}

	@Override
	public void run(ApplicationArguments args) throws Exception {
		refreshSysFuncStore();
		refreshRoleFuncStore();
		
	}

	
}
